#ifndef _BSPLINE_H
#define _BSPLINE_H
#include "QList"
#include "QPoint"
#include "QPainter"
#include "QPainterPath"
template<typename Point>
class BSpline
{
private:
	double precision = 0.001; //你可以自己设置精度，确保所画直线的细腻程度
	QList<Point> * pointList;
private:
	void AllBernstein(int n, double u, double *B);
	Point PointOnBYTCurve(double u);
	double getC(int n1, int j);
public:
	BSpline();
	~BSpline();
	void setPrecision(double precision);
	void appendPoint(Point point);
	QPainterPath getPainterPath();
	double getPrecision();
};

template<typename Point>
BSpline<Point>::BSpline()
{
    pointList = new QList<Point>;
}

template<typename Point>
BSpline<Point>::~BSpline()
{
    delete pointList;
}


template<typename Point>
void BSpline<Point>::appendPoint(Point point)
{
    pointList->append(point);
}
template<typename Point>

QPainterPath BSpline<Point>::getPainterPath()
{
    QPainterPath path;

    for (double t = 0; t<1; t += precision)
    {
        Point pTemp = PointOnBYTCurve(t);
        if (t == 0.0) path.moveTo(pTemp);
        path.lineTo(pTemp);
    }
    return path;
}

template<typename Point>
void BSpline<Point>::setPrecision(double precision)
{
    if (precision<1)
        this->precision = precision;
}

template<typename Point>

double BSpline<Point>::getPrecision()
{
    return this->precision;
}
template<typename Point>
void BSpline<Point>::AllBernstein(int n, double u, double *B)
{
    double xishu = 1;
    for (int i = 2; i <= n; i++)
        xishu *= i;
    for (int k = 0; k <= n; k++)
    {
        B[k] = 0.0;
        for (int j = 0; j <= n - k; j++)
        {
            double temp = 0.0;
            temp = j % 2 == 0 ? 1 : -1;
            temp *= getC(n + 1, j);
            temp *= pow((u + n - k - j), n);
            B[k] += temp;
        }
        B[k] /= xishu;
    }
}
template<typename Point>
double BSpline<Point>::getC(int n1, int j) {
    double res = 1;
    for (int t = 1, n2 = n1; t <= j; t++) {
        res *= n2;
        n2--;
    }
    for (int t = 1; t <= j; t++)
        res /= t;
    return res;
}
template<typename Point>
Point BSpline<Point>::PointOnBYTCurve(double u)
{
    int n = pointList->length();
    double *coefficient = new double[n]; //系数数组
    memset(coefficient, 0, sizeof(coefficient));
    AllBernstein(n - 1, u, coefficient);//计算系数
    Point tempPoint(0.0, 0.0);
    for (int i = 0; i<pointList->length(); i++)
    {
        Point temp = pointList->at(i);
        tempPoint = tempPoint + temp*coefficient[i];
    }
    return tempPoint;
}

#endif
